package cmap

import (
	"github.com/pkg/errors"
	"math"
	"sync/atomic"
)

type Cmap interface {
	Set(key string,value interface{})(bool,error)
	Get(key string)interface{}
	Delete(key string)(bool)
	Concurrency()int
	Total()uint64
}
type myCmap struct {
	segments []Segment
	total uint64
}

func NewCmap(concurrency int,minBucketNum int,maxBucketSize uint64)(Cmap,error)  {
	if concurrency <=0{
		return nil,errors.New("concurrency must gt zero")
	}
	cmap := &myCmap{}
	cmap.segments = make([]Segment,concurrency)
	for i:= 0;i<concurrency;i++ {
		cmap.segments[i],_ = NewSegment(minBucketNum,maxBucketSize)
	}
	return cmap,nil
}
func (this *myCmap)Total()uint64  {
	return atomic.LoadUint64(&this.total)
}
func (this *myCmap)Concurrency()int  {
	return len(this.segments)
}
func (this *myCmap)findSegment(key string)Segment  {
	if len(this.segments) == 1{
		return this.segments[0]
	}
	hash := hash(key)
	var keyHash uint32
	if hash > math.MaxUint32{
		keyHash = uint32(hash>>32)
	}else{
		keyHash = uint32(hash)
	}
	return this.segments[int(keyHash>>16)%(len(this.segments)-1)]
}
func (this *myCmap)Set(key string,value interface{})(bool,error)  {
	segment := this.findSegment(key)
	item := NewItem(key,value)
	ok ,err := segment.Set(item)
	if ok{
		atomic.AddUint64(&this.total,1)
	}
	return ok,err
}
func (this *myCmap)Get(key string)interface{}  {
	segment := this.findSegment(key)
	item := segment.Get(key)
	return item
}
func (this *myCmap)Delete(key string)(bool)  {
	segment := this.findSegment(key)
	return  segment.Delete(key)
}